﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Goodway.Dao.Utility;
using System.Xml.Linq;
using ExcelImportComponent.Valider;
using Goodway.Common;
using Goodway.Data;
using System.Web;
using System.Configuration;
using System.IO;

namespace ExcelImportComponent
{
    public class ExcelImporter
    {
        public GoodwayEntity Setting { get; private set; }

        public string ExcelUrl { get; private set; }

        public bool IsValid { get; private set; }

        public bool IsLive { get; set; }

        private bool isPreView = false;

        private List<GoodwayEntity> importData;

        public List<GoodwayEntity> ExcelData { get; private set; }

        public int StartRowCount { get; private set; }

        public XDocument Document { get; private set; }

        private string schemaname = "{http://tempuri.org/}";
        
        public ExcelImporter(string settingId, string excelUrl)
        {
            IGoodwayEntityProvider provider = GoodwayEntityProviderFactory.GetEntityProvider();
            provider.TableName = "XmlImportSetting";
            provider.ConStr = "CostCntString";
            this.Setting = provider.Get(settingId);
            this.ExcelUrl = excelUrl;
            this.IsValid = false;
            this.IsLive = true;
        }

        public List<ExcelImportValidMessage> DoValid()
        {
            try
            {
                if (!IsLive) throw new Exception("该对象已经关闭");
                string path = SysUtility.GetGloablFile(@"ImportSetting\" + this.Setting["XmlSettingName"]);


                XDocument document = XDocument.Load(path);

                this.Document = document;

                var tableSetting = document.Descendants(schemaname + "ImportSetting").First();
                int rowCount = int.Parse(tableSetting.Attribute("StartRow").Value);
                this.StartRowCount = rowCount;
                string tableName = tableSetting.Attribute("TableName").Value;
                string dataSourceKey = tableSetting.Attribute("DataSourceKey").Value;
                string sheetName = tableSetting.Attribute("SheetName").Value;

                IGoodwayEntityProvider provider = GoodwayEntityProviderFactory.GetEntityProvider("excel");
                string strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + this.ExcelUrl + ";Extended Properties='Excel 12.0 xml;HDR=No;IMEX=1'";
                provider.ConStr = strCon;
                provider.TableName = sheetName;

                this.ExcelData = provider.GetAll();

                for (int i = 0; i < this.StartRowCount; i++)
                {
                    this.ExcelData.RemoveAt(0);
                }

                List<ExcelImportValidMessage> list = new List<ExcelImportValidMessage>();

                if (ExcelData.Count > 0)
                {
                    var Columns = from column in document.Descendants(schemaname + "Column") select column;

                    foreach (XElement node in Columns)
                    {
                        string col = node.Attribute("Col").Value;
                        foreach (XElement valid in node.Descendants(schemaname + "Valid"))
                        {
                            string name = valid.Attribute("Name").Value;
                            IVaild valider = ValiderFactory.GetValider(name.ToLower());
                            List<ExcelImportValidMessage> rightList = valider.DoValid(col, ExcelData, valid, schemaname);
                            list = this.MergeValidMessage(list, rightList);
                        }
                    }
                }
                this.IsValid = list.Count == 0;
                return list;
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        public List<GoodwayEntity> DoPreView()
        {
            if (!IsLive) throw new Exception("该对象已经关闭");
            if (!IsValid) throw new Exception("验证成功后才可以预览");

            var Columns = this.Document.Descendants(schemaname + "Column");
            var tableSetting = Document.Descendants(schemaname + "ImportSetting").First();
            var pkSetting = tableSetting.Element(schemaname + "PK");

            if (pkSetting == null) throw new Exception("请设置主键");
            if (pkSetting.Attribute("Name") == null) throw new Exception("请设置主键IDName");
            if (pkSetting.Attribute("IsGuid") == null && pkSetting.Attribute("IdFactoryKey") == null) throw new Exception("请设置主键生成方式");

            if (tableSetting.Attribute("TableName") == null) throw new Exception("请设置表名");
            if (tableSetting.Attribute("DataSourceKey") == null) throw new Exception("请设置数据库名");

            string pkName = pkSetting.Attribute("Name").Value;
            bool isGuid = pkSetting.Attribute("IsGuid") != null;

            string tableName = tableSetting.Attribute("TableName").Value;
            string dataSourceKey = tableSetting.Attribute("DataSourceKey").Value;
            int Id = 0;

            Dictionary<string, List<GoodwayEntity>> enumDic = new Dictionary<string, List<GoodwayEntity>>();

            if (!isGuid)
            {
                Id = GetPKId(tableName); 
            }

            List<GoodwayEntity> entities = new List<GoodwayEntity>();
            foreach (GoodwayEntity data in ExcelData)
            {
                GoodwayEntity entity = new GoodwayEntity();
                entity.TableName = tableName;
                entity.ConStr = dataSourceKey;
                if (isGuid)
                {
                    entity[pkName] = Guid.NewGuid().ToString();
                }
                else
                {
                    Id++;
                    entity[pkName] = Id.ToString();
                }

                foreach (XElement column in Columns)
                {
                    XElement enumValid = column.Descendants(schemaname + "Valid").FirstOrDefault(p => p.Attribute("Name").Value == "DataType.Enum");
                    XElement fkValid = column.Descendants(schemaname + "Valid").FirstOrDefault(p => p.Attribute("Name").Value == "FK");
                    bool isEnum = enumValid != null;
                    bool isFK = fkValid != null;
                    string columnName = column.Attribute("Name").Value;
                    string col = column.Attribute("Col").Value;
                    if (isEnum)
                    {
                        string textColumnName = column.Attribute("TextName") == null ? "" : column.Attribute("TextName").Value;
                        string enumDataSourceKey = enumValid.Attribute("DataSourceKey").Value;
                        string enumKey = enumValid.Attribute("EnumKey").Value;
                        string dicEnumKey = enumDataSourceKey + "." + enumKey;
                        if (!string.IsNullOrEmpty(data[col]))
                        {
                            if (!enumDic.ContainsKey(dicEnumKey))
                            {
                                string strSql = string.Format("select * from EnumItem where EnumKey='{0}'", enumKey);
                                IGoodwayEntityProvider provider = GoodwayEntityProviderFactory.GetEntityProvider();
                                provider.ConStr = enumDataSourceKey;
                                enumDic.Add(dicEnumKey, provider.GetBySql(strSql));
                            }
                            List<GoodwayEntity> enumEntityList = enumDic[dicEnumKey];

                            GoodwayEntity enumEntity = enumEntityList.First(p => p["EnumText"] == data[col]);
                            entity[columnName] = enumEntity["EnumValue"];

                            if (!string.IsNullOrEmpty(textColumnName))
                            {
                                entity[textColumnName] = enumEntity["EnumText"];
                            }
                        }
                        else
                        {
                            entity[columnName] = "";
                        }
                    }
                    else if (isFK)
                    {
                        string textColumnName = column.Attribute("TextName").Value;
                        string fkDataSourceKey = fkValid.Attribute("DataSourceKey").Value;
                        string pkColumnName = fkValid.Attribute("PK").Value;
                        string fkTableName = fkValid.Attribute("TableName").Value;
                        string fkTextColumnName = fkValid.Attribute("TextColumn").Value;


                        string dicKey = fkDataSourceKey + "." + fkTableName;
                        if (!string.IsNullOrEmpty(data[col]))
                        {
                            if (!enumDic.ContainsKey(dicKey))
                            {
                                string strSql = string.Format("select * from {0}", fkTableName);
                                IGoodwayEntityProvider provider = GoodwayEntityProviderFactory.GetEntityProvider();
                                provider.TableName = fkTableName;
                                provider.ConStr = fkDataSourceKey;
                                enumDic.Add(dicKey, provider.GetBySql(strSql));
                            }
                            List<GoodwayEntity> enumEntityList = enumDic[dicKey];
                            GoodwayEntity enumEntity = enumEntityList.First(p => p[fkTextColumnName] == data[col]);
                            entity[textColumnName] = enumEntity[fkTextColumnName];
                            entity[columnName] = enumEntity[pkColumnName];
                        }
                        else
                        {
                            entity[columnName] = "";
                        }
                    }
                    else
                    {
                        entity[columnName] = data[col];
                    }
                }
                entities.Add(entity);
            }
            this.isPreView = true;

            importData = entities;
            return entities;
        }

        public List<GoodwayEntity> GetPreViewList()
        {
            List<GoodwayEntity> returnValue = new List<GoodwayEntity>();
            var columns = Document.Descendants(schemaname + "Column");
            foreach (GoodwayEntity entity in this.ExcelData)
            {
                GoodwayEntity newEntity = new GoodwayEntity();
                foreach (XElement column in columns)
                {
                    if (column.Attribute("Des") != null)
                    {
                        var col = column.Attribute("Col").Value;
                        var des = column.Attribute("Des").Value;
                        newEntity[des] = entity[col];
                    }
                }
                returnValue.Add(newEntity);

            }
            return returnValue;
        }

        public void DoImport()
        {
            if (!IsLive) throw new Exception("该对象已经关闭");
            if (!IsValid) throw new Exception("验证成功后才可以导入");
            if (!isPreView)
            {
                importData = DoPreView();
            }
            IGoodwayEntityProvider provider = GoodwayEntityProviderFactory.GetEntityProvider();
            foreach (GoodwayEntity entity in importData)
            {
                provider.TableName = entity.TableName;
                provider.ConStr = entity.ConStr;
                provider.Insert(entity);
            }
        }

        /// <summary>
        /// 根据数据表名称获取最大Id
        /// </summary>
        /// <param name="tablename"></param>
        /// <returns></returns>
        public int GetPKId(string tablename)
        {
            string SqlStr = "select select max(Id) from {0}";

            object Id = new DbAccess("CostCntString").QueryValue(string.Format(SqlStr, tablename));

            if (Id != null)
            {
                return Convert.ToInt32(Id);
            }

            return 1;
        }

        private List<ExcelImportValidMessage> MergeValidMessage(List<ExcelImportValidMessage> firstMessage, List<ExcelImportValidMessage> secondMessage)
        {
            List<ExcelImportValidMessage> returnValue = new List<ExcelImportValidMessage>();
            foreach (ExcelImportValidMessage message in firstMessage)
            {
                ExcelImportValidMessage newMessage = message.Clone();
                ExcelImportValidMessage sameMessage = secondMessage.FirstOrDefault(p => p.X == newMessage.X && p.Y == newMessage.Y);
                if (sameMessage != null)
                {
                    newMessage.ErrorMessage.AddRange(sameMessage.ErrorMessage.ToArray());
                }
                returnValue.Add(newMessage);
            }

            foreach (ExcelImportValidMessage message in secondMessage)
            {
                ExcelImportValidMessage newMessage = message.Clone();
                ExcelImportValidMessage sameMessage = firstMessage.FirstOrDefault(p => p.X == newMessage.X && p.Y == newMessage.Y);
                if (sameMessage == null)
                {
                    returnValue.Add(newMessage);
                }
            }
            return returnValue;
        }

    }

    public class SysUtility
    {
        public SysUtility()
        {
        }
        
        public static string FormatMoney(string money, decimal UnitNum)
        {
            decimal num = 0M;
            if (!string.IsNullOrEmpty(money))
            {
                num = Convert.ToDecimal(money) * UnitNum;
            }
            return num.ToString();
        }

        public static List<KeyValuePair<string, string>> GetContextStringList(HttpContext context, string condition, bool isFull, bool isRemoveCondition)
        {
            List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
            foreach (string str in context.Request.QueryString.Keys)
            {
                bool flag = false;
                if (isFull)
                {
                    if (str == condition)
                    {
                        flag = true;
                    }
                }
                else if (str.IndexOf(condition) >= 0)
                {
                    flag = true;
                }
                if (flag)
                {
                    string key = str;
                    if (isRemoveCondition)
                    {
                        key = str.Replace(condition, "");
                    }
                    KeyValuePair<string, string> item = new KeyValuePair<string, string>(key, context.Request.QueryString[str]);
                    list.Add(item);
                }
            }
            return list;
        }

        public static string GetFullPath(string parentFullId, string Id)
        {
            if (string.IsNullOrEmpty(parentFullId))
            {
                return Id;
            }
            return (parentFullId + "." + Id);
        }

        public static string GetGloablFile(string filePath)
        {
            string str = ConfigurationManager.AppSettings["DALPath"] ?? AppDomain.CurrentDomain.BaseDirectory;
            bool flag = true;
            while (!File.Exists(str + filePath))
            {
                int num = str.LastIndexOf(@"\", (int)(str.Length - 2));
                if (num < 0)
                {
                    throw new Exception(string.Format("File Name {0} 不存在", filePath));
                }
                str = str.Substring(0, num + 1);
            }
            if (flag)
            {
                str = str + filePath;
            }
            return str;
        }
        
        public static string UndoFormatMoney(string money, decimal UnitNum)
        {
            decimal num = 0M;
            if (!string.IsNullOrEmpty(money))
            {
                num = Convert.ToDecimal(money) / UnitNum;
            }
            return num.ToString();
        }

    }
}
